package registnet.cpm;

import java.util.List;
import java.util.Vector;

/**
 * An implementation of a project.
 */
public class Project {

	/**
	 * The name of the project.
	 */
	private String name;
	
	/**
	 * The list of the nodes for the network diagram representing the project.
	 */
	private List<Node> nodes = new Vector<Node>();
	
	/**
	 * The list of the arcs for the network diagram representing the project.
	 */
	private List<Arc> arcs = new Vector<Arc>();
	
	/**
	 * The duration of the project.
	 */
	private int projectDuration;
	
	/**
	 * Creates a project with the given name.
	 * @param name
	 */
	public Project(String name){
		this.name = name;
	}
	
	/**
	 * Sets the name of the project.
	 * @param name
	 */
	public void setName(String name){
		this.name = name;
	}
	
	/**
	 * Returns the name of the project.
	 * @return the name of the project
	 */
	public String getName(){
		return this.name;
	}
	
	/**
	 * Adds a node to the list of nodes.
	 * @param node
	 */
	public void addNode(Node node){
		this.nodes.add(node);
	}
	
	/**
	 * Returns the list of nodes.
	 * @return
	 */
	public List<Node> getNodes(){
		return this.nodes;
	}
	
	/**
	 * Sets the list of arcs.
	 * @param arc
	 */
	public void addArc(Arc arc){
		this.arcs.add(arc);
	}
	
	/**
	 * Returns the list of arcs.
	 * @return the list of arcs
	 */
	public List<Arc> getArcs(){
		return this.arcs;
	}

	/**
	 * Returns the project activity duration.
	 * @return the project activity duration
	 */
	public int getProjectDuration() {
		return projectDuration;
	}

	/**
	 * Sets the project activity duration
	 * @param projectDuration
	 */
	public void setProjectDuration(int projectDuration) {
		this.projectDuration = projectDuration;
	}
	
	/**
	 * Checks if the given node has a predecessor node.
	 * @param node
	 * @return true if the given node has a predecessor node, and false otherwise
	 */
	public boolean hasPredecessor(Node node){
		for(int i=0; i<this.getArcs().size(); i++)
			if(this.getArcs().get(i).getEndNode().equals(node))
				return true;
		return false;
	}
	
	/**
	 * Checks if the given node has a successor node.
	 * @param node
	 * @return true if the given node has a successor node, and false otherwise
	 */
	public boolean hasSuccessor(Node node){
		for(int i=0; i<this.getArcs().size(); i++)
			if(this.getArcs().get(i).getStartNode().equals(node))
				return true;
		return false;
	}
	
	/**
	 * Returns the list of predecessor nodes of the given node
	 * @param node
	 * @return the list of predecessor nodes of the given node
	 */
	public List<Node> getPredecessors(Node node){
		List<Node> retval = new Vector<Node>();
		for(int i=0; i<this.getArcs().size(); i++)
			if(this.getArcs().get(i).getEndNode().equals(node))
				retval.add(this.getArcs().get(i).getStartNode());
		return retval;
	}
	
	/**
	 * Returns the list of successor nodes of the given node
	 * @param node
	 * @return the list of successor nodes of the given node
	 */
	public List<Node> getSuccessors(Node node){
		List<Node> retval = new Vector<Node>();
		for(int i=0; i<this.getArcs().size(); i++)
			if(this.getArcs().get(i).getStartNode().equals(node))
				retval.add(this.getArcs().get(i).getEndNode());
		return retval;
	}
	
	/**
	 * Returns a list of the starting nodes. Starting nodes are nodes that have no predecessor nodes.
	 * @return a list of the starting nodes
	 */
	public List<Node> getStartNodes(){
		List<Node> retval = new Vector<Node>();
		for(int i=0; i<this.getNodes().size(); i++)
			if(!hasPredecessor(this.getNodes().get(i))) 
				retval.add(this.getNodes().get(i));
		return retval;
	}
	
	/**
	 * Returns a list of the end nodes. End nodes are nodes that have no successor nodes.
	 * @return a list of the end nodes
	 */
	public List<Node> getEndNodes(){
		List<Node> retval = new Vector<Node>();
		for(int i=0; i<this.getNodes().size(); i++)
			if(!hasSuccessor(this.getNodes().get(i))) 
				retval.add(this.getNodes().get(i));
		return retval;
	}
	
	/**
	 * Returns the index of the node in the list of nodes.
	 * @param node
	 * @return the index of the node in the list of nodes
	 */
	public int getIndex(Node node){
		for(int i=0; i<this.getNodes().size(); i++)
			if(this.getNodes().get(i).equals(node)) return i;
		return -1;
	}
	
	/**
	 * Computes the activity duration of all the activities.
	 */
	public void computeActivityDuration(){
		this.projectDuration = 0;
		for(int i=0; i<this.getNodes().size(); i++)
			if(this.getNodes().get(i).getEarlyFinish() > projectDuration)
				this.projectDuration = this.getNodes().get(i).getEarlyFinish();
	}
	
	/**
	 * Returns the list of nodes with slack time equal to the given slack time.
	 * @param slack
	 * @return the list of nodes with slack time equal to the given slack time
	 */
	public List<Node> getNodes(int slack){
		List<Node> retval = new Vector<Node>();
		for(int i=0; i<this.getNodes().size(); i++)
			if(this.getNodes().get(i).getSlack() == slack) 
				retval.add(this.getNodes().get(i));
		return retval;
	}
	
	/**
	 * Returns the node with the given name
	 * @param name
	 * @return
	 */
	public Node getNode(String name){
		for(int i=0; i<this.getNodes().size(); i++)
			if(this.getNodes().get(i).getName().equals(name)) 
				return getNodes().get(i);
		return null;
	}
	
	/**
	 * Checks if a node with the given name is present in the list of nodes.
	 * @param name
	 * @return true if a node with the given name is present in the list of nodes, and false otherwise.
	 */
	public boolean hasNode(String name){
		for(int i=0; i<this.getNodes().size(); i++)
			if(this.getNodes().get(i).getName().equals(name)) 
				return true;
		return false;
	}
	
	/**
	 * Prints the basic information about the network diagram that represents the project.
	 */
	public void print(){
		System.out.println("[check] NODES: <name>");
		for(int i=0; i<this.getNodes().size(); i++)
			System.out.println("[check] node: "+getNodes().get(i).getName());
		System.out.println("[check] ARCS: <startNode>-<endNode>");
		for(int i=0; i<this.getArcs().size(); i++)
			System.out.println("[check] arc: "+getArcs().get(i).getName());
	}
	
}
